﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper.QueryableExtensions;
using Jy.Abp.Application;
using Jy.Abp.Auditing;
using Jy.Abp.Authorization;
using Jy.Abp.Extensions;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Repositories;

namespace Jy.Abp.GeneralTree;

public abstract class GeneralTreeAppServiceBase<TEntity, TKey, TFilter, TPageFilter, TEditDto, TListItem, TDto> : AppService<TEntity, TKey>
    where TEntity : class, IGeneralTree<TEntity, TKey>
    where TKey : struct
    where TFilter : GeneralTreeFilter<TKey>
    where TPageFilter : GeneralTreeListFilter<TKey>
    where TEditDto : GeneralTreeEditDto<TKey>
    where TListItem : GeneralTreeListDto<TKey>
    where TDto : GeneralTreeDto<TDto, TKey>, IGeneralTreeDto<TDto, TKey>
{
    protected readonly IGeneralTreeManager<TEntity, TKey> TreeManager;
    protected virtual string GetListPolicyName { get; set; }
    protected virtual string GetTreePolicyName { get; set; }
    protected virtual string CreatePolicyName { get; set; }
    protected virtual string UpdatePolicyName { get; set; }
    protected virtual string DeletePolicyName { get; set; }
    public GeneralTreeAppServiceBase(
        IGeneralTreeManager<TEntity, TKey> treeManager,
        IRepository<TEntity, TKey> treeRepository)
        : base(treeRepository)
    {
        TreeManager = treeManager;
    }

    /// <summary>
    /// 设置权限
    /// </summary>
    protected virtual void SetManagePermission(object permission)
    {
        if (permission == null)
            return;
        var strPermission = PermissionHelper.GetPermissionName(permission);
        CreatePolicyName = strPermission;
        UpdatePolicyName = strPermission;
        DeletePolicyName = strPermission;
        GetListPolicyName = strPermission;
    }
    /// <summary>
    /// 映射创建实体
    /// </summary>
    protected virtual TEntity Map(TEditDto dto)
    {
        return ObjectMapper.Map<TEditDto, TEntity>(dto);
    }
    /// <summary>
    /// 映射修改实体
    /// </summary>
    protected virtual void Map(TEditDto dto, TEntity entity)
    {
        ObjectMapper.Map(dto, entity);
    }
    /// <summary>
    /// 获取查询对像
    /// </summary>
    protected virtual async Task<IQueryable<TEntity>> GetQueryAsync()
    {
        return await Repository.GetQueryableAsync();
    }
    /// <summary>
    /// 获取查询对像
    /// </summary>
    protected virtual async Task<IQueryable<TEntity>> GetQueryAsync(TFilter filter)
    {
        return await GetQueryAsync();
    }
    /// <summary>
    /// 获取查询对像
    /// </summary>
    protected virtual async Task<IQueryable<TEntity>> GetQueryAsync(TPageFilter filter)
    {
        return await GetQueryAsync();
    }

    #region 接口
    /// <summary>
    /// 获取所有分类数据（包含下级）
    /// </summary>
    public virtual async Task<IEnumerable<TDto>> GetTreeAsync(TFilter filter)
    {
        await CheckPolicyAsync(GetTreePolicyName ?? GetListPolicyName);

        var items = await (await GetQueryAsync(filter))
                .WhereIf(filter.ParentCode.HasValue(), x => x.Code.StartsWith(filter.ParentCode))
                .ToListAsync(AsyncExecuter);

        return ObjectMapper.Map<List<TEntity>, List<TDto>>(items)
                   .ToTreeOrderBy<TDto, TKey, string>(x => x.Code)
                   .ToList();
    }
    /// <summary>
    /// 获取列表
    /// </summary>
    public virtual async Task<PagedResultDto<TListItem>> GetListAsync(TPageFilter filter)
    {
        await CheckPolicyAsync(GetListPolicyName);

        var query = (await GetQueryAsync(filter))
            .WhereIf(filter.ParentCode.HasValue(), t => t.Code.StartsWith(filter.ParentCode))
            .WhereIf(filter.Keywords.HasValue(), t => t.Name.Contains(filter.Keywords))
            .ProjectTo<TListItem>(ObjectMapper);
        filter.SetDefaultSortIfNot(nameof(IHasCreationTime.CreationTime));
        return await CreatePagedResultAsync(query, filter);
    }
    /// <summary>
    /// 创建
    /// </summary>
    [AuditTag("创建")]
    public virtual async Task<TDto> CreateAsync(TEditDto dto)
    {
        await CheckPolicyAsync(CreatePolicyName);
        var entity = Map(dto);
        await TreeManager.CreateAsync(entity);
        return ObjectMapper.Map<TEntity, TDto>(entity);
    }
    /// <summary>
    /// 修改
    /// </summary>
    [AuditTag("修改")]
    public virtual async Task<TDto> UpdateAsync(TKey id, TEditDto dto)
    {
        await CheckPolicyAsync(UpdatePolicyName);
        var entity = await Repository.GetAsync(id);
        //源父ID
        var sourceParentId = entity.ParentId;
        var sourceName = entity.Name;
        //更新数据
        Map(dto, entity);
        //移动到指定父类
        if (!sourceParentId.Equals(dto.ParentId))
            await TreeManager.MoveToAsync(id, dto.ParentId);
        //更新了名称
        if (sourceName != entity.Name)
            await TreeManager.UpdateNameAsync(entity);
        return ObjectMapper.Map<TEntity, TDto>(entity);
    }
    /// <summary>
    /// 删除 
    /// </summary>
    [AuditTag("删除")]
    public virtual async Task DeleteAsync(TKey id)
    {
        await CheckPolicyAsync(DeletePolicyName);
        await TreeManager.DeleteAsync(id);
    }
    #endregion
}
